// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Components/ControllerComponent.h"
#include "GameplayTagContainer.h"

#include "LyraWeaponStateComponent.generated.h"

class UObject;
struct FFrame;
struct FGameplayAbilityTargetDataHandle;
struct FGameplayEffectContextHandle;
struct FHitResult;

// 命中标记在准星中显示远程武器的影响
// "成功"的命中标记显示对敌人造成伤害的影响
/**
 * 屏幕空间命中位置结构体
 */
struct FLyraScreenSpaceHitLocation
{
	/** 视口屏幕空间中的命中位置 */
	FVector2D Location;	
	// 命中区域标签
	FGameplayTag HitZone;
	// 是否显示为成功
	bool bShowAsSuccess = false;
};

/**
 * 服务器端命中标记批次结构体
 */
struct FLyraServerSideHitMarkerBatch
{
	// 默认构造函数
	FLyraServerSideHitMarkerBatch() { }

	// 带唯一ID的构造函数
	FLyraServerSideHitMarkerBatch(uint8 InUniqueId) :
		UniqueId(InUniqueId)
	{ }

	// 命中标记数组
	TArray<FLyraScreenSpaceHitLocation> Markers;
	// 唯一ID
	uint8 UniqueId = 0;
};

// 跟踪武器状态和最近确认的命中标记以在屏幕上显示
/**
 * 武器状态组件，跟踪武器状态和命中标记
 */
UCLASS()
class ULyraWeaponStateComponent : public UControllerComponent
{
	GENERATED_BODY()

public:
	// 构造函数
	ULyraWeaponStateComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

	/**
	 * 重写的组件Tick函数。
	 */
	virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	/**
	 * 客户端确认目标数据（可靠，客户端函数）。
	 * @param UniqueId 唯一ID
	 * @param bSuccess 是否成功
	 * @param HitReplaces 命中替换索引数组
	 */
	UFUNCTION(Client, Reliable)
	void ClientConfirmTargetData(uint16 UniqueId, bool bSuccess, const TArray<uint8>& HitReplaces);

	/**
	 * 添加未确认的服务器端命中标记。
	 * @param InTargetData 目标数据句柄
	 * @param FoundHits 找到的命中结果
	 */
	void AddUnconfirmedServerSideHitMarkers(const FGameplayAbilityTargetDataHandle& InTargetData, const TArray<FHitResult>& FoundHits);

	/** 更新此玩家的最后造成伤害时间 */
	void UpdateDamageInstigatedTime(const FGameplayEffectContextHandle& EffectContext);

	/** 获取此玩家最近造成武器伤害的位置数组，在屏幕空间中 */
	void GetLastWeaponDamageScreenLocations(TArray<FLyraScreenSpaceHitLocation>& WeaponDamageScreenLocations)
	{
		WeaponDamageScreenLocations = LastWeaponDamageScreenLocations;
	}

	/** 返回自上次（传出）伤害命中通知发生以来经过的时间 */
	double GetTimeSinceLastHitNotification() const;

	// 获取未确认的服务器端命中标记数量
	int32 GetUnconfirmedServerSideHitMarkerCount() const
	{
		return UnconfirmedServerSideHitMarkers.Num();
	}

protected:
	/**
	 * 过滤命中结果以确定是否应将其视为成功命中
	 * 默认行为是，如果对属于与拥有控制器Pawn不同团队的团队Actor执行，则将其视为成功
	 */
	virtual bool ShouldShowHitAsSuccess(const FHitResult& Hit) const;

	/**
	 * 检查是否应更新造成伤害时间。
	 */
	virtual bool ShouldUpdateDamageInstigatedTime(const FGameplayEffectContextHandle& EffectContext) const;

	// 实际更新造成伤害时间
	void ActuallyUpdateDamageInstigatedTime();

private:
	/** 此控制器最后造成武器伤害的时间 */
	double LastWeaponDamageInstigatedTime = 0.0;

	/** 我们最近造成武器伤害的屏幕空间位置（已确认的命中） */
	TArray<FLyraScreenSpaceHitLocation> LastWeaponDamageScreenLocations;

	/** 未确认的命中 */
	TArray<FLyraServerSideHitMarkerBatch> UnconfirmedServerSideHitMarkers;
};